#!/usr/bin/env python
# encoding: utf-8
"""
@author: youfeng
@email: youfeng243@163.com
@license: Apache Licence
@file: proxy_handler_.py
@time: 2017/12/20 10:19
"""

# 代理管理对象
import random
import threading
import time

import requests

from common import util
from config.proxy_conf import DYNAMIC_PROXY_CONF, STATIC_PROXY_URL, GATEWAY_PROXY_URL, GateWayType


# 代理使用总入口
class ProxyHandler(object):
    # 单例
    __instance = None

    # 更新线程句柄
    __static_update_thread = None

    def __init__(self, proxy_type=GateWayType.GATEWAY_ALL, log=None):

        self.log = log

        self.log.info("初始化代理信息...")

        # 管理现在可用的静态代理
        self.__static_proxy_list = self.__update_static_proxy(test=False)
        self.__static_length = len(self.__static_proxy_list)
        self.__static_point = random.randint(0, self.__static_length)

        # 静态代理更新线程
        self.__static_update_thread = threading.Thread(target=self.__static_update_run, )
        self.__static_update_thread.setDaemon(True)
        self.__static_update_thread.start()

        # 获取的代理类型
        self.proxy_type = proxy_type

        self.log.info("代理初始化完成...")

    # 更新静态代理
    def __update_static_proxy(self, test=True):

        for _ in xrange(3):
            proxy_list = []
            try:
                r = requests.get(STATIC_PROXY_URL, timeout=10)
                if r is None or r.status_code != 200:
                    self.log.error("更新静态代理网络异常...")
                    continue

                line_list = r.text.strip().split('\n')
                for line in line_list:
                    line = line.strip().strip("\r").strip("\n")
                    if len(line) <= 0:
                        continue

                    proxy = {'http': line}
                    # if '7777' in line:
                    #     new_line = line.replace('7777', '55555')
                    #     proxy['http'] = 'socks5://' + new_line
                    # elif '8088' in line:
                    #     new_line = line.replace('8088', '1088')
                    #     proxy['http'] = 'socks5://' + new_line

                    if test:
                        try:
                            resp = requests.get("http://bigdata.sz.haizhi.com/", proxies=proxy, timeout=5)
                            if resp is None or resp.status_code != 200 or "知识图谱" not in resp.text:
                                self.log.error("当前静态代理不可用: proxy = {}".format(proxy))
                                continue

                        except Exception as e:
                            self.log.error("当前静态代理不可用: proxy = {}".format(proxy))
                            self.log.exception(e)
                            continue

                    proxy_list.append(proxy)
                self.log.info('静态代理更新代理成功: length = {}'.format(len(proxy_list)))
                return proxy_list
            except Exception as e:
                self.log.error('访问静态代理链接异常: ')
                self.log.exception(e)
        return []

    # 静态代理更新线程
    def __static_update_run(self):

        self.log.info("启动静态代理更新线程...")

        while True:
            # 更新静态代理
            static_proxy_list = self.__update_static_proxy(test=False)

            static_proxy_length = len(static_proxy_list)
            if static_proxy_length > 0:
                self.__static_proxy_list = static_proxy_list
                self.__static_length = static_proxy_length
                self.log.info("更新静态代理完成: __static_length = {}".format(self.__static_length))

            self.log.info("完成静态代理更新, 休眠3600秒")

            # 每隔1个小时更新一次
            time.sleep(random.randint(3600, 4600))

    # 获得代理接口
    def get_random_proxy(self, host):

        proxy = self.__get_gateway_proxy(host)
        if proxy is None or len(proxy) <= 0:
            return self.__get_static_proxy()

        return proxy

    # 获得网关代理
    def __get_gateway_proxy(self, host):
        for _ in xrange(3):
            try:
                r = requests.get(GATEWAY_PROXY_URL.format(self.proxy_type, host),
                                 timeout=10)
                if r is None or r.status_code != 200:
                    time.sleep(1)
                    self.log.warn("代理网关访问异常, 重试...")
                    continue

                proxy_dict = util.json_loads(r.text)
                if proxy_dict.get("status") != "ok":
                    time.sleep(1)
                    self.log.warn("代理网关获取代理异常: text = {}".format(r.text))
                    continue

                proxy = proxy_dict.get("proxy")
                if proxy is None:
                    time.sleep(1)
                    self.log.warn("代理网关获取代理异常: text = {}".format(r.text))
                    continue

                self.log.info('网关 ip = {}'.format(proxy))
                proxies = {'http': proxy}
                return proxies
            except Exception as e:
                self.log.error("动态代理访问异常:")
                self.log.exception(e)
                time.sleep(1)
        return {}

    # 获取代理
    def __get_dynamic_proxy(self, host):

        for _ in xrange(3):
            try:
                r = requests.get('http://{}:{}/proxy/{}'.format(
                    DYNAMIC_PROXY_CONF['host'],
                    DYNAMIC_PROXY_CONF['port'],
                    host),
                    timeout=10)
                if r is None or r.status_code != 200 or 'failed' in r.text or 'False' in r.text:
                    time.sleep(1)
                    self.log.warn("动态代理服务异常, 重试...")
                    continue

                self.log.info('鲲鹏 ip = {ip}'.format(ip=r.text))
                proxies = {'http': 'http://{host}'.format(host=r.text)}
                return proxies
            except Exception as e:
                self.log.error("动态代理访问异常:")
                self.log.exception(e)
                time.sleep(1)
        return {}

    # 获取静态代理
    def __get_static_proxy(self):

        if self.__static_point >= self.__static_length:
            self.__static_point = 0

        try:
            if self.__static_length > 0:
                proxy = self.__static_proxy_list[self.__static_point]
                self.__static_point += 1
                self.log.info('静态代理 ip = {}'.format(proxy))
                return proxy

            self.log.error("当前静态代理长度为空: __static_length = {} actual length = {}".format(
                self.__static_length, len(self.__static_proxy_list)))
            self.__static_length = len(self.__static_proxy_list)
        except Exception as e:
            self.log.error("静态代理取址失败: point = {} cur length = {} actual length = {}".format(
                self.__static_point, self.__static_length, len(self.__static_proxy_list)))
            self.log.exception(e)
            return {}

        return {}
